import base64
import hashlib
from datetime import datetime, timedelta

from captcha.views import CaptchaStore, captcha_image
from django.conf import settings
from django.contrib import auth
from django.contrib.auth import login
from django.shortcuts import redirect
from django.utils.translation import gettext_lazy as _
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers
from rest_framework.status import HTTP_401_UNAUTHORIZED
from rest_framework.views import APIView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

from application import dispatch
from dvadmin.system.models import Users
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
from dvadmin.utils.request_util import save_login_log
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.validator import CustomValidationError
from random import randint


class CaptchaView(APIView):
    authentication_classes = []
    permission_classes = []

    @swagger_auto_schema(
        responses={"200": openapi.Response("Get successful")},
        security=[],
        operation_id="captcha-get",
        operation_description="Captcha get",
    )
    def get(self, request):
        data = {}
        if dispatch.get_system_config_values("base.captcha_state"):
            hashkey = CaptchaStore.generate_key()
            id = CaptchaStore.objects.filter(hashkey=hashkey).first().id
            imgage = captcha_image(request, hashkey)
            # Convert image to base64
            image_base = base64.b64encode(imgage.content)
            data = {
                "key": id,
                "image_base": "data:image/png;base64," + image_base.decode("utf-8"),
            }
        return DetailResponse(data=data)


class LoginSerializer(TokenObtainPairSerializer):
    """
    Login serializer:
    Override the serializer of djangorestframework-simplejwt
    """
    captcha = serializers.CharField(
        max_length=6, required=False, allow_null=True, allow_blank=True
    )

    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]

    default_error_messages = {"no_active_account": _("Invalid username/password")}

    def validate(self, attrs):

        captcha = self.initial_data.get("captcha", None)
        if dispatch.get_system_config_values("base.captcha_state"):
            if captcha is None:
                raise CustomValidationError("Captcha cannot be empty")
            self.image_code = CaptchaStore.objects.filter(
                id=self.initial_data["captchaKey"]
            ).first()
            five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
            if self.image_code and five_minute_ago > self.image_code.expiration:
                self.image_code and self.image_code.delete()
                raise CustomValidationError("Captcha expired")
            else:
                if self.image_code and (
                        self.image_code.response == captcha
                        or self.image_code.challenge == captcha
                ):
                    self.image_code and self.image_code.delete()
                else:
                    self.image_code and self.image_code.delete()
                    raise CustomValidationError("Invalid captcha")
        data = super().validate(attrs)
        data["name"] = self.user.name
        data["userId"] = self.user.id
        data["avatar"] = self.user.avatar
        data['user_type'] = self.user.user_type
        dept = getattr(self.user, 'dept', None)
        if dept:
            data['dept_info'] = {
                'dept_id': dept.id,
                'dept_name': dept.name,

            }
        role = getattr(self.user, 'role', None)
        if role:
            data['role_info'] = role.values('id', 'name', 'key')
        request = self.context.get("request")
        request.user = self.user
        # Record login log
        save_login_log(request=request)
        # Whether single sign-on is enabled
        if dispatch.get_system_config_values("base.single_login"):
            # Add the token of the previously logged-in user to the blacklist
            user = Users.objects.filter(id=self.user.id).values('last_token').first()
            last_token = user.get('last_token')
            if last_token:
                try:
                    token = RefreshToken(last_token)
                    token.blacklist()
                except:
                    pass
            # Save the latest token to the user table
            Users.objects.filter(id=self.user.id).update(last_token=data.get('refresh'))
        return {"code": 2000, "msg": "Request successful", "data": data}

class AppLoginSerializer(TokenObtainPairSerializer):
    """
    App login serializer:
    Override the serializer of djangorestframework-simplejwt
    """
    captcha = serializers.CharField(
        max_length=6, required=False, allow_null=True, allow_blank=True
    )

    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]

    default_error_messages = {"no_active_account": _("Invalid username/password")}

    def validate(self, attrs):

        # captcha = self.initial_data.get("captcha", None)
        # if dispatch.get_system_config_values("base.captcha_state"):

        data = super().validate(attrs)
        data["name"] = self.user.name
        data["userId"] = self.user.id
        data["avatar"] = self.user.avatar
        data['userType'] = self.user.user_type
        dept = getattr(self.user, 'dept', None)
        if dept:
            data['dept_info'] = {
                'dept_id': dept.id,
                'dept_name': dept.name,

            }
        role = getattr(self.user, 'role', None)
        if role:
            data['roleInfo'] = role.values('id', 'name', 'key')
        request = self.context.get("request")
        request.user = self.user
        # Record login log
        save_login_log(request=request)
        # Whether single sign-on is enabled
        if dispatch.get_system_config_values("base.single_login"):
            # Add the token of the previously logged-in user to the blacklist
            user = Users.objects.filter(id=self.user.id).values('last_token').first()
            last_token = user.get('last_token')
            if last_token:
                try:
                    token = RefreshToken(last_token)
                    token.blacklist()
                except:
                    pass

        # Save the latest token to the user table
        Users.objects.filter(id=self.user.id).update(last_token=data.get('refresh'))
        # serializer = UsersModelSerializerInvert(data)
        # Use the method of DjangoRestSerializer to convert underscores to camel case
        # camel_case_data = serializer.data
        return {"code": 2000, "msg": "Request successful", "data": data}


class CustomTokenRefreshView(TokenRefreshView):
    """
    Custom token refresh
    """

    def post(self, request, *args, **kwargs):
        refresh_token = request.data.get("refresh")
        try:
            token = RefreshToken(refresh_token)
            data = {
                "access": str(token.access_token),
                "refresh": str(token)
            }
        except:
            return ErrorResponse(status=HTTP_401_UNAUTHORIZED)
        return DetailResponse(data=data)


class LoginView(TokenObtainPairView):
    """
    Login interface
    """
    serializer_class = LoginSerializer
    permission_classes = []

class AppLoginView(TokenObtainPairView):
    """
    Login interface
    """
    serializer_class = AppLoginSerializer
    permission_classes = []

class AppCaptchaView(TokenObtainPairView):
    """
    Get verification code interface
    """

    # For generating a 4-digit random verification code
    def generate_code(self) -> int:
        return randint(1000, 9999)

        # Send email interface
        # def post(self):
        #     user_email = self.get_body_argument('email')  # Get the email input by the front-end form
        #     msg = f'Hello, you are registering for the <CMS forum project> user registration on {user_email}. Your verification code is {self.generate_code()}. If it is not you, please ignore'
        #     send_mail(email.get('uname'), email.get('pwd'), user_email, '<CMS forum project> user registration', msg)

class UsersModelSerializerInvert(serializers.ModelSerializer):
    class Meta:
        model = Users
        fields = '__all__'  # Or specify the list of fields to be serialized

class LoginTokenSerializer(TokenObtainPairSerializer):
    """
    Login serializer:
    """

    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]

    default_error_messages = {"no_active_account": _("Invalid username/password")}

    def validate(self, attrs):
        if not getattr(settings, "LOGIN_NO_CAPTCHA_AUTH", False):
            return {"code": 4000, "msg": "This interface is not available!", "data": None}
        data = super().validate(attrs)
        data["name"] = self.user.name
        data["userId"] = self.user.id
        serializer = UsersModelSerializerInvert(data)
        # Use the method of DjangoRestSerializer to convert underscores to camel case
        camel_case_data = serializer.data
        return {"code": 2000, "msg": "Request successful", "data": camel_case_data}


class LoginTokenView(TokenObtainPairView):
    """
    Login get token interface
    """
    queryset = Users.objects.all()
    # serializer_class = UserSerializer

    serializer_class = LoginTokenSerializer
    permission_classes = []


class LogoutView(APIView):
    def post(self, request):
        Users.objects.filter(id=self.request.user.id).update(last_token=None)
        return DetailResponse(msg="Logout successful")


class ApiLoginSerializer(CustomModelSerializer):
    """Interface document login-serializer"""

    username = serializers.CharField()
    password = serializers.CharField()

    class Meta:
        model = Users
        fields = ["username", "password"]


class ApiLogin(APIView):
    """Interface document login interface"""

    serializer_class = ApiLoginSerializer
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        username = request.data.get("username")
        password = request.data.get("password")
        user_obj = auth.authenticate(
            request,
            username=username,
            password=hashlib.md5(password.encode(encoding="UTF-8")).hexdigest(),
        )
        if user_obj:
            login(request, user_obj)
            return redirect("/")
        else:
            return ErrorResponse(msg="Invalid username/password")
